﻿using ff14bot;
using ff14bot.Behavior;
using ff14bot.Helpers;
using ff14bot.Managers;
using ff14bot.Navigation;
using ff14bot.Objects;
using TreeSharp;

using Action = TreeSharp.Action;

namespace Magitek.Helpers
{
    public class Casting
    {
        public delegate T Selection<out T>(object context);
        public static Composite Cast(Selection<string> spell, Selection<bool> reqs = null, Selection<GameObject> onTarget = null, Selection<int> nonspam = null, Selection<bool> doublecast = null)
        {
            return new Decorator(ret =>
            {
                if (!Actionmanager.HasSpell(spell(ret)))
                    return false;

                if (reqs != null && !reqs(ret))
                    return false;

                GameObject target = onTarget != null ? onTarget(ret) : Core.Player.CurrentTarget;

                if (target == null)
                    return false;

                if (!Actionmanager.CanCast(spell(ret), target))
                    return false;

                if (Extensions.DoubleCastPreventionDict.Contains(target, spell(ret)))
                    return false;

                SpellData data;
							
                var result = Actionmanager.CurrentActions.TryGetValue(spell(ret), out data);

//to fix stupid new queueing thing preventing preemption
				if(data.Cooldown.TotalMilliseconds >= 50)
					return false;
				
                if (result)
                {
                    var castTime = data.AdjustedCastTime.TotalSeconds > 0;
                    if (castTime && (MovementManager.IsMoving || Core.Player.IsCasting))
                    {
                        return false;
                    }

                }

                return true;


            }, new Action(ret =>
            {

                var castingSpell = Core.Player.SpellCastInfo;

//commented out to prevent new queueing thing from canceling manually casted spells

/*                if (castingSpell != null && castingSpell.IsSpell && castingSpell.SpellData.Name != spell(ret) && castingSpell.SpellData.Name != "Shadow Flare")
                    Actionmanager.StopCasting();
*/
                if (!BotManager.Current.IsAutonomous && MovementManager.IsMoving)
                    Navigator.PlayerMover.MoveStop();

                GameObject target = onTarget != null ? onTarget(ret) : Core.Player.CurrentTarget;

                Logging.Write("[Magitek] Casting " + spell(ret));

                if (Actionmanager.DoAction(spell(ret), target))
                {
                    if (doublecast != null && doublecast(ret))
                        Extensions.UpdateDoubleCastDict(spell(ret), target);

                    Magitek.WindowSettings.lastspellused = spell(ret);
                }

                new WaitContinue(nonspam(ret), r => (Core.Player.SpellCastInfo == null), new ActionAlwaysSucceed());

                return RunStatus.Success;

            }));
        }
        public static Composite PetCast(Selection<GameObject> target, Selection<string> spell, Selection<bool> reqs = null)
        {
            return new Decorator(ret =>
            {
                if (Core.Player.Pet == null)
                    return false;

                if (reqs != null && !reqs(ret))
                    return false;

                if (!Pet.CanCast(spell(ret), target(ret)))
                    return false;

                return true;


            }, new Action(ret =>
            {

                Pet.DoAction(spell(ret), target(ret));

                if (spell(ret) == "Sic" || spell(ret) == "Obey")
                {
                    return RunStatus.Success;   
                }

                return RunStatus.Failure;

            }));
            
        }
        public static Composite Heal(Selection<string> spell, Selection<bool> reqs = null, Selection<GameObject> onTarget = null, Selection<int> nonspam = null, Selection<bool> doublecast = null)
        {
            return new Decorator(ret =>
            {

                if (reqs != null && !reqs(ret))
                    return false;

                if (!Actionmanager.HasSpell(spell(ret)))
                    return false;

                GameObject target = onTarget != null ? onTarget(ret) : Core.Player.CurrentTarget;

                if (target == null)
                    return false;

                if (!Actionmanager.CanCast(spell(ret), target))
                    return false;

                if (Extensions.HealDoubleCastPreventionDict.Contains(target, spell(ret)))
                    return false;

                SpellData data;
                var result = Actionmanager.CurrentActions.TryGetValue(spell(ret), out data);
                if (result)
                {
                    var castTime = data.AdjustedCastTime.TotalSeconds > 0;
                    if (castTime && MovementManager.IsMoving)
                    {
                        return false;
                    }

                }

                return true;


            }, new Action(ret =>
            {
                if (Magitek.WindowSettings.ToggleClericStance && Core.Player.HasAura("Cleric Stance"))
                    Actionmanager.DoAction("Cleric Stance", Core.Player);

                var castingSpell = Core.Player.SpellCastInfo;
                if (castingSpell != null && castingSpell.IsSpell && castingSpell.SpellData.Name != spell(ret) && castingSpell.SpellData.Name != "Shadow Flare")
                    Actionmanager.StopCasting();

                if (!BotManager.Current.IsAutonomous && MovementManager.IsMoving)
                    Navigator.PlayerMover.MoveStop();

                GameObject target = onTarget != null ? onTarget(ret) : Core.Player.CurrentTarget;

                Logging.Write("[Magitek] Casting " + spell(ret) + " on target => " + target.Name);

                if (Actionmanager.DoAction(spell(ret), target))
                {
                    if (doublecast != null && doublecast(ret))
                        Extensions.HealUpdateDoubleCastDict(spell(ret), target);
                }

                return RunStatus.Success;

            }));
        }
      
    }
}

